use std::fs::{self, OpenOptions};
use std::io::{self, Write};
use std::path::Path;
use regex::Regex;

/// 自动路由构建器
fn main() -> io::Result<()> {
    // 目标文件路径
    let dest_path = Path::new("src/apps/auto_routes.rs");

    // 打开文件并截断内容，如果文件不存在则创建
    let mut file = OpenOptions::new().write(true).truncate(true).create(true).open(&dest_path)?;
    println!("Opened and cleared file: {:?}", dest_path);

    // 应用层级目录
    let apps_path = Path::new("src/apps");

    // 路由代码字符串
    let mut imports_code = String::new();
    let mut routes_code = String::new();

    // Rust 关键字列表
    let keywords = [
        "as", "break", "const", "continue", "crate", "else", "enum", "extern", "false", "fn",
        "for", "if", "impl", "in", "let", "loop", "match", "mod", "move", "mut", "pub", "ref",
        "return", "self", "static", "struct", "super", "trait", "true", "type", "unsafe",
        "use", "where", "while",
    ];

    // 匹配路由函数的正则表达式，支持常见的 HTTP 方法和异步/非异步函数
    let route_fn_regex = Regex::new(r"#[\[](get|post|put|delete|patch|options|head)\([^\)]*\)[\]]\s*pub\s*(async\s*)?fn\s*([a-zA-Z0-9_]+)").unwrap();

    // 扫描指定的应用层级目录
    println!("Starting scan of apps directory: {:?}", apps_path);
    for entry in fs::read_dir(apps_path)? {
        let entry = entry?;
        let path = entry.path();
        if path.is_dir() {
            scan_dir(&path, &route_fn_regex, &keywords, &mut imports_code, &mut routes_code)?;
        }
    }

    // 构造最终的路由代码
    let mut final_routes_code = String::new();
    final_routes_code.push_str("// Automatically scan for routes auto_routes.rs\n\n");
    final_routes_code.push_str(&imports_code);
    final_routes_code.push_str("\npub fn apps_auto_routes() -> Vec<rocket::Route> {\n");
    final_routes_code.push_str("    use rocket_okapi::openapi_get_routes;\n\n");
    final_routes_code.push_str("    openapi_get_routes![\n");
    final_routes_code.push_str(&routes_code);
    final_routes_code.push_str("    ]\n");
    final_routes_code.push_str("}\n");

    // 写入到目标文件
    file.write_all(final_routes_code.as_bytes())?;
    println!("Wrote routes to file: {:?}", dest_path);

    // 检查并更新同级目录下的 mod.rs 文件
    let mod_path = dest_path.with_file_name("mod.rs");
    if mod_path.exists() {
        let mut mod_content = fs::read_to_string(&mod_path)?;
        if !mod_content.contains("pub mod auto_routes;") {
            mod_content.push_str("\npub mod auto_routes;\n");
            fs::write(&mod_path, mod_content)?;
            println!("Updated mod.rs to include pub mod auto_routes;");
        } else {
            println!("mod.rs already includes pub mod auto_routes;");
        }
    } else {
        println!("mod.rs does not exist, creating it.");
        let mut mod_file = OpenOptions::new().write(true).create(true).open(&mod_path)?;
        mod_file.write_all(b"pub mod auto_routes;\n")?;
        println!("Created mod.rs with pub mod auto_routes;");
    }

    Ok(())
}

// 获取应用模块名称
fn get_module_name(path: &Path) -> Option<String> {
    let mut current_path = path.parent();
    while let Some(p) = current_path {
        if p.file_name().unwrap() == "controller" {
            if let Some(parent) = p.parent() {
                return parent.file_name().map(|n| n.to_string_lossy().to_string());
            }
        }
        current_path = p.parent();
    }
    None
}


// 递归扫描目录并生成路由代码
fn scan_dir(path: &Path, route_fn_regex: &Regex, keywords: &[&str], imports_code: &mut String, routes_code: &mut String) -> io::Result<()> {
    if path.is_dir() {
        println!("Scanning directory: {:?}", path);
        for entry in fs::read_dir(path)? {
            let entry = entry?;
            let path = entry.path();
            println!("Found entry: {:?}", path);
            if path.is_dir() {
                scan_dir(&path, route_fn_regex, keywords, imports_code, routes_code)?;
            } else if path.is_file() {
                let file_name = path.file_stem().unwrap().to_str().unwrap();
                if file_name == "mod" {
                    continue; // 跳过 mod.rs 文件
                }
                let module_name = if keywords.contains(&file_name) {
                    format!("r#{}", file_name)
                } else {
                    file_name.to_string()
                };
                if let Some(parent_dir_name) = get_module_name(&path) {
                    println!("Importing module: {}::{}", parent_dir_name, module_name);
                    imports_code.push_str(&format!("use crate::apps::{parent}::controller::{module};\n", parent = parent_dir_name, module = module_name));
                    let content = fs::read_to_string(&path)?;
                    routes_code.push_str(&format!("        // {module}\n", module = module_name));
                    for cap in route_fn_regex.captures_iter(&content) {
                        let fn_name = &cap[3];
                        println!("Found route function: {}::{}", module_name, fn_name);
                        routes_code.push_str(&format!("        {module}::{function},\n", module = module_name, function = fn_name));
                    }
                    routes_code.push_str("\n");
                }
            }
        }
    }
    Ok(())
}
